iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0
自我挑戰組

30天FUME TO FHIR轉換實戰 - 從入門到燃燒殆盡系列 第 16

[FUME TO FHIR] 16 FUME 簡介,其他Converter概述(firely SDK)

  • 分享至 

  • xImage
  •  

VI.FUME

16 FUME 簡介,其他Converter概述(firely SDK)

今天要開始來介紹FUME這個FHIR Converter,也是系列文下半部的主要議題

在正式開始這個主題之前,我想先談談其他的Converter,

先前提到過的Firely,其釋出的SDK中就有包含了FHIR的各種Resource的物件用法,

ex:

FhirBoolean b = new() { ObjectValue = "treu" };
Patient p = new() { Contact = new() [ new Patient.ContactComponent() ], ActiveElement = b };


{
  "resourceType": "Patient",
  "active": "treu",
  "contact": [{}]
}

關於firely SDK可以看一下他們的Documentation,如果是用C#開發的可以直接引入使用,在開發界接上會快一點
https://docs.fire.ly/projects/Firely-NET-SDK/en/latest/index.html

再來是另一個Converter,是Lorex開發的FHIR Universal Conversion Kit, 簡稱F.U.C.K <-註:請把.標好
https://github.com/Lorex/FHIR-Universal-Conversion-Kit

原則上他的邏輯會和FUME更靠近一些,以node.js開發,同樣支援REST Request與直接執行轉換,

先前沒有使用這一套轉換器的原因是在Mapping開發上會比較花時間一點,但node.js的支援性會比FUME FLASH再好一些,

另一個原因是FUME的開發界面比較容易上手,至於最終讀者想要嘗試哪個轉換器應該都能有效的輸出預期的成品。

這個專案我會認為有一個比FUME好的地方是,他在後期處理的支援比FUME還多一些,支援驗證文件與自動上傳,相較之下FUME把他弄去付費版了orz

其實應該這種產品要非常多的,事實上各大FHIR Server的開發公司,smile, Microsoft, Google等都有自己的一套FHIR Converter,

但是大多數的FHIR Converter都是針對既有格式的轉換,如CDA -> FHIR, HL7 v2 -> FHIR,

這樣子的好處是,各國的醫療院所能夠很簡單的從一個舊標準轉成一個新標準,這很好。

可是把話題繞回來,最開始我們提到了,醫療院所的醫資系統大多都是自己開發的,欄位與內容也都是自定義,本身的資料使用就不遵循HL7 v2等標準,
和國際上長期使用v2等標準不同,因此這些標準間轉換的轉換器顯然並不符合我們的需求,我們需要一個可以把散落的資料轉FHIR格式,且開發簡單快速好使用的轉換器

在面對需求的當下,筆者有嘗試過用node.js進行HardCoding,但越做越覺得開發成本巨大,而且並不能很好的覆蓋需求,

在面對多種選擇但進度毫無進展的當下,我決定採用FUME來開發,

FUME 是由以色列的醫資公司 Outburn.health開發的工具,於DevDays 2024正式發表,專案以Typescript開發
https://outburn.health/fhir-converter/

並且是開源工具,可以經由REST的方式進行轉換,

FUME由兩個部分組成 - FUME Engine與FUME Designer,後者是GUI的開發界面,可以及時回應轉換內容,
唯一可惜的是FUME Designer是需要付費的,與FUME Enterprise版本綑綁在一起,雖然是這樣說
FUME Designer提供了一個線上版本的playground可以測試撰寫的內容與轉換的結果

https://try.fume.health/

其實乍聽之下FUME與F.U.C.K能提供的功能非常相近,甚至後者還支援更多,那筆者為何使用FUME來開發,

FUME使用了一種混合語言做為映射結構(FUME Mapping)稱作FUME FLASH,這個FUME FLASH是將JSONata與FHIR ShortHand(FSH)合併使用的一種新語言,

FHIR的結構描述部分由FSH來處理;運算與資料處理則由JSONata來執行,

這個混合語言帶來了一個很直接的好處是,開發FUME Mapping非常直觀,這邊是一個很簡單的範例(FUME Designer預設):


Instance: $pid := $uuid()
 InstanceOf: Patient
 * identifier
   * system = $urn
   * value = 'urn:uuid:' & $pid
 * identifier
   * system = $exampleMrn
   * value = mrn
 * identifier
   * system = $ssn
   * value = ssn
 * identifier
   * system = $passportPrefix & passport_country
   * value = passport_number
 * active = status='active'
 * name
   * given = first_name
   * family = last_name
 * birthDate = birth_date
 * gender = $translate(sex, 'gender')
 * (address).address
   * city = city_name
   * state = state
   * country = 'USA'
   * line = $join([$string(house_number),street_name], ' ')
   * postalCode = zip_code
   * extension
  * url = $extGeolocation
  * extension
    * url = 'latitude'
    * valueDecimal = lat
  * extension
    * url = 'longitude'
    * valueDecimal = long
 * (phones).telecom
   * system = 'phone'
   * value = number
   * use = (type='HOME'?'home':type='CELL'?'mobile')
 * generalPractitioner
   * identifier
  * value = primary_doctor.license
  * type.coding
    * system = 'http://terminology.hl7.org/CodeSystem/v2-0203'
    * code = 'MD'
   * display = primary_doctor.full_name
   * reference = $literal('Practitioner', {'identifier': primary_doctor.license})

可以看到,撰寫的方式跟閱讀IG的Profile模式是一致的,看到哪一行就寫到哪一行,非常直覺。

而輸入的部分也非常簡單直接:

{
  "mrn": "PP875023983",
  "status": "active",
  "ssn": "123-45-6789",
  "passport_number": "7429184766",
  "passport_country": "USA",
  "first_name": "Jessica",
  "last_name": "Rabbit",
  "birth_date": "1988-06-22",
  "sex": "F",
  "address": {
    "city_name": "Orlando",
    "state": "FL",
    "street_name": "Buena Vista",
    "house_number": 1375,
    "zip_code": "3456701",
    "lat": 28.3519592,
    "long": -81.417283
  },
  "phones": [
    {
      "type": "HOME",
      "number": "+1 (407) 8372859"
    },
    {
      "type": "CELL",
      "number": "+1 (305) 9831195"
    }
  ],
  "primary_doctor": {
    "full_name": "Dr. Dolittle",
    "license": "1-820958"
  }
}

{
  "resourceType": "Patient",
  "id": "65611b12-6032-4f9a-ba02-622dd0556226",
  "identifier": [
    {
      "system": "urn:ietf:rfc:3986",
      "value": "urn:uuid:65611b12-6032-4f9a-ba02-622dd0556226"
    },
    {
      "system": "http://this.is.an.example.uri/mrn",
      "value": "PP875023983"
    },
    {
      "system": "http://hl7.org/fhir/sid/us-ssn",
      "value": "123-45-6789"
    },
    {
      "system": "http://hl7.org/fhir/sid/passport-USA",
      "value": "7429184766"
    }
  ],
  "active": true,
  "name": [
    {
      "given": [
        "Jessica"
      ],
      "family": "Rabbit"
    }
  ],
  "birthDate": "1988-06-22",
  "gender": "female",
  "address": [
    {
      "city": "Orlando",
      "state": "FL",
      "country": "USA",
      "line": [
        "1375 Buena Vista"
      ],
      "postalCode": "3456701",
      "extension": [
        {
          "url": "http://hl7.org/fhir/StructureDefinition/geolocation",
          "extension": [
            {
              "url": "latitude",
              "valueDecimal": 28.3519592
            },
            {
              "url": "longitude",
              "valueDecimal": -81.417283
            }
          ]
        }
      ]
    }
  ],
  "telecom": [
    {
      "system": "phone",
      "value": "+1 (407) 8372859",
      "use": "home"
    },
    {
      "system": "phone",
      "value": "+1 (305) 9831195",
      "use": "mobile"
    }
  ],
  "generalPractitioner": [
    {
      "identifier": {
        "value": "1-820958",
        "type": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/v2-0203",
              "code": "MD"
            }
          ]
        }
      },
      "display": "Dr. Dolittle",
      "reference": "Practitioner/fume-example-doctor"
    }
  ]
}

這樣子的轉換在Playground的響應時間不到1秒,幾乎是轉瞬完成。

關於FLASH這個語言實際上要注意的東西還真的滿不少的,很多機制是筆者在反覆撰寫實作的過程中摸索出來的,

基本上FUME是完整支援JSONata的使用方式的,所以若有無法實現出來的功能不妨閱讀一下JSONata的Documentation
https://docs.jsonata.org/overview.html

那說了這麼多好處,開發看起來也很容易很爽,那有沒有缺點呢?

有,其實也不少,大多數目前筆者遇到的麻煩大概都是沒付錢(?)上企業版,從驗證、上傳FHIR Server、快取與即時響應等都是企業版的服務範圍,
但最直接影響到的是開發便利帶來的轉換速度犧牲,以筆者目前實作事前審查IG而言,若無快取輔助在社群版(免費版)的轉換時間大約需要20-30秒,
雖然快取能讓之後的轉換時間落在1秒以內,但這樣的速度並不令人滿意,

值得注意的是,付費版似乎很好的處理掉這個問題了,以同樣的FUME Mapping在FUME Designer Playground的實測表現來說,轉換響應僅需要不到3秒,
如果大的性能差距確實令人心癢。

我會在後面的部分詳細說明這個語言個人的使用方法,但筆者也並不是完整的摸透了它,若有不足會再編輯補充。


上一篇
[FUME TO FHIR] 15 FHIR Validation(官方Validator、Inferno)
下一篇
[FUME TO FHIR] 17 FUME Designer
系列文
30天FUME TO FHIR轉換實戰 - 從入門到燃燒殆盡30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言